package com.bestcem.xm.qdes.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.bestcem.xm.common.core.constant.ReqErrorCodeConstants;
import com.bestcem.xm.common.core.domain.web.XmResultJson;
import com.bestcem.xm.component.mybatis.service.impl.XmServiceImpl;
import com.bestcem.xm.component.security.context.SecurityContextHolder;
import com.bestcem.xm.qdes.controller.param.ShareUserParam;
import com.bestcem.xm.qdes.controller.vo.QdesProjectentryVo;
import com.bestcem.xm.qdes.entity.QdesProjectEntry;
import com.bestcem.xm.qdes.grpc.client.UserGrpcClient;
import com.bestcem.xm.qdes.grpc.client.dto.UserDto;
import com.bestcem.xm.qdes.grpc.v1.services.ProjectEntryPermType;
import com.bestcem.xm.qdes.mapper.QdesProjectEntryMapper;
import com.bestcem.xm.qdes.mq.dto.StatusDto;
import com.bestcem.xm.qdes.mq.send.biz.QdesMessageSendService;
import com.bestcem.xm.qdes.service.QdesProjectEntryService;
import com.google.common.collect.MapDifference;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

import static com.bestcem.xm.qdes.enums.ProjectBadgeStatusEnum.PROJECTENTRY_BADGE_STATUS_UNREAD;
import static com.bestcem.xm.qdes.grpc.v1.services.ProjectEntryCategory.PROJECTENTRY_CATEGORY_FELLOWER;

@Service
@Slf4j
@RequiredArgsConstructor
public class QdesProjectEntryServiceImpl extends XmServiceImpl<QdesProjectEntryMapper, QdesProjectEntry> implements QdesProjectEntryService {

    private @NonNull UserGrpcClient userGrpcClient;

    private @NonNull QdesMessageSendService qdesMessageSendService;

    @Override
    public List<QdesProjectentryVo> getShareUsers(String id) {
        List<QdesProjectEntry> projectEntryList = this.getQdesProjectEntryList(id);
        if (CollUtil.isEmpty(projectEntryList)) {
            return Collections.emptyList();
        }
        List<QdesProjectentryVo> list = new ArrayList<>();
        //此处粗略设置容量
        Map<String, UserDto> userMap = new HashMap<>();
        projectEntryList.forEach(v -> {
            QdesProjectentryVo qdesProjectentryVo = new QdesProjectentryVo();
            qdesProjectentryVo.setUserId(v.getUserId());
            UserDto userDTO = userMap.computeIfAbsent(v.getUserId(), s -> {
                //根据userId获取分享者信息
                return userGrpcClient.getUser(v.getUserId());
            });
            qdesProjectentryVo.setName(userDTO.getUsername());
            qdesProjectentryVo.setEmail(userDTO.getEmail());
            qdesProjectentryVo.setTtype(v.getPermType());
            userDTO = userMap.computeIfAbsent(v.getCreatorId(), s -> {
                //根据creatorId获取创建者名称
                return userGrpcClient.getUser(v.getCreatorId());
            });
            qdesProjectentryVo.setCreator(userDTO.getUsername());
            qdesProjectentryVo.setCreatedDt(v.getCreatedDt());
            list.add(qdesProjectentryVo);
        });
        return list;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public XmResultJson<?> shareUsers(String id, ShareUserParam shareUserParam) {
        String userId = SecurityContextHolder.getUserId();
        String orgId = SecurityContextHolder.getOrgId();
        //获取原来的分享列表
        List<QdesProjectEntry> oldProjectList = this.getQdesProjectEntryList(id);
        Map<String, Object[]> oldEntrys = new HashMap<>();
        //此处去重导致顺序有问题
        oldProjectList.forEach(v -> oldEntrys.put(v.getUserId(), new Object[]{JSONArray.parseArray(v.getPermissionsArry()).toJavaList(Integer.class)
                .stream().distinct().collect(Collectors.toList()).toString(), v.getPermType()}));
        List<ShareUserParam.Projects> projectList = Optional.ofNullable(shareUserParam.getProjects()).orElse(Collections.emptyList());
        Map<String, Object[]> newEntrys = new HashMap<>(projectList.size() * 2);
        for (ShareUserParam.Projects projects : projectList) {
            String uid = projects.getUserId();
            if (StringUtils.isEmpty(uid)) {
                return XmResultJson.fail(ReqErrorCodeConstants.PARAM_LOST, ":user_id is required");
            }
            //如果permission没有变更，前端不会传对应的permission字段，所以需要获取old_entrys
            if (CollUtil.isEmpty(projects.getPermissionsArray())) {
                newEntrys.put(uid, Optional.ofNullable(oldEntrys.get(uid)).orElse(new Object[]{}));
            } else {
                newEntrys.put(uid, new Object[]{Optional.ofNullable(projects.getPermissionsArray().toString()).orElse(Collections.emptyList().toString()),
                        Optional.ofNullable(projects.getTtype()).orElse(ProjectEntryPermType.PROJECTENTRY_PERM_TYPE_CUSTOM.getNumber())});
            }
        }
        //当前管理员的权限信息
        QdesProjectEntry projectEntry = getQdesProjectManager(id, userId);
        Set<String> add = new HashSet<>();
        Set<String> put = new HashSet<>();
        Set<String> del;
        //Maps.difference(Map, Map)用来比较两个Map以获取所有不同点。该方法返回MapDifference对象
        MapDifference<String, Object[]> difference = Maps.difference(newEntrys, oldEntrys);
        // 键只存在于左边Map的映射项，用于新增
        Map<String, Object[]> currentEntrys = difference.entriesOnlyOnLeft();
        if (CollUtil.isNotEmpty(currentEntrys)) {
            QdesProjectEntry qdesProjectentry = new QdesProjectEntry();
            qdesProjectentry.setOrgId(orgId);
            qdesProjectentry.setProjectId(id);
            qdesProjectentry.setTitle(projectEntry.getTitle());
            qdesProjectentry.setCategory(PROJECTENTRY_CATEGORY_FELLOWER.getNumber());
            qdesProjectentry.setStatus(projectEntry.getStatus());
            qdesProjectentry.setBadgeStatus(PROJECTENTRY_BADGE_STATUS_UNREAD.getValue());
            qdesProjectentry.setCreatorId(userId);
            currentEntrys.forEach((k, v) -> {
                QdesProjectEntry entry = new QdesProjectEntry();
                BeanUtils.copyProperties(qdesProjectentry, entry);
                entry.setUserId(k);
                entry.setPermissionsArry(v[0].toString());
                entry.setPermType((Integer) v[1]);
                entry.setFolderId(Optional.ofNullable(entry.getFolderId()).orElse(""));
                baseMapper.insert(entry);
            });
            add = currentEntrys.keySet();
        }
        // 键只存在于右边Map的映射项，用于删除
        del = difference.entriesOnlyOnRight().keySet();
        //删除的被分享人
        if (CollUtil.isNotEmpty(del)) {
            LambdaQueryWrapper<QdesProjectEntry> queryWrapper = Wrappers.lambdaQuery();
            queryWrapper.eq(QdesProjectEntry::getProjectId, id);
            queryWrapper.in(QdesProjectEntry::getUserId, del);
            baseMapper.delete(queryWrapper);
            JSONObject dto = new JSONObject();
            dto.put("user_ids", del);
            dto.put("project_id", id);
            qdesMessageSendService.projectDeletedShareSend(dto);
        }
        //两者交集，用于更新，分享权限修改
        Sets.SetView<String> intersection = Sets.intersection(newEntrys.keySet(), oldEntrys.keySet());
        if (CollUtil.isNotEmpty(intersection)) {
            QdesProjectEntry updateProjectentry = new QdesProjectEntry();
            intersection.forEach(k -> {
                Object[] newObject = newEntrys.get(k);
                Object[] oldObject = oldEntrys.get(k);
                if (!(newObject[0].equals(oldObject[0]) && newObject[1].equals(oldObject[1]))) {
                    //更新的被分享人
                    LambdaQueryWrapper<QdesProjectEntry> queryWrapper = Wrappers.lambdaQuery();
                    queryWrapper.eq(QdesProjectEntry::getProjectId, id);
                    queryWrapper.eq(QdesProjectEntry::getUserId, k);
                    updateProjectentry.setPermissionsArry(newObject[0].toString());
                    updateProjectentry.setPermType((Integer) newObject[1]);
                    baseMapper.update(updateProjectentry, queryWrapper);
                    put.add(k);
                }
            });
        }
        Map<String, Object> data = new HashMap<>(4);
        data.put("add", add);
        data.put("put", put);
        data.put("del", del);
        Map<String, Object> res = new HashMap<>(2);
        res.put("data", data);
        //更新问卷时间
        qdesMessageSendService.projectUpdatedSend(new StatusDto().setProjectId(id));
        return XmResultJson.success(res);
    }

    List<QdesProjectEntry> getQdesProjectEntryList(String id) {
        LambdaQueryWrapper<QdesProjectEntry> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(QdesProjectEntry::getProjectId, id);
        queryWrapper.eq(QdesProjectEntry::getCategory, PROJECTENTRY_CATEGORY_FELLOWER.getNumber());
        queryWrapper.orderByDesc(QdesProjectEntry::getUpdatedDt);
        queryWrapper.last("limit 10000");
        return baseMapper.selectList(queryWrapper);
    }

    QdesProjectEntry getQdesProjectManager(String id, String userId) {
        LambdaQueryWrapper<QdesProjectEntry> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(QdesProjectEntry::getProjectId, id);
        queryWrapper.eq(QdesProjectEntry::getUserId, userId).last("limit 1");
        return baseMapper.selectOne(queryWrapper);
    }
}
